/******************************************************************************* * Copyright (c) 2004, 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.dnd; //import java.util.ArrayList; //import java.util.Iterator; //import java.util.List; import org.eclipse.jface.util.Geometry; //import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; //import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; //import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; //import org.eclipse.swt.widgets.Tracker; //import org.eclipse.ui.PlatformUI; //import org.eclipse.ui.internal.DragCursors; /** * Provides the methods for attaching drag-and-drop listeners to SWT controls. */ public class DragUtil { // RAP [rh] DnD not implemented // private static final String DROP_TARGET_ID = "org.eclipse.ui.internal.dnd.dropTarget"; //$NON-NLS-1$ // RAP [rh] DnD not implemented // /** // * The location where all drags will end. If this is non-null, then // * all user input is ignored in drag/drop. If null, we use user input // * to determine where objects should be dropped. // */ // private static TestDropLocation forcedDropTarget = null; // RAP [rh] DnD not implemented // /** // * List of IDragOverListener // */ // private static List defaultTargets = new ArrayList(); // RAP [rh] DnD not implemented // /** // * Sets the drop target for the given control. It is possible to add one or more // * targets for a "null" control. This becomes a default target that is used if no // * other targets are found (for example, when dragging objects off the application // * window). // * // * @param control the control that should be treated as a drag target, or null // * to indicate the default target // * @param target the drag target to handle the given control // */ // public static void addDragTarget(Control control, IDragOverListener target) { // if (control == null) { // defaultTargets.add(target); // } else { // List targetList = getTargetList(control); // // if (targetList == null) { // targetList = new ArrayList(1); // } // targetList.add(target); // control.setData(DROP_TARGET_ID, targetList); // } // } // RAP [rh] DnD not implemented // /** // * Return the list of 'IDragOverListener' elements associated with // * the given control. If there's a 'global' listener then always // * return it. // * // * @param control // * @return // */ // private static List getTargetList(Control control) { // List result = (List) control.getData(DROP_TARGET_ID); // return result; // } // RAP [rh] DnD not implemented // /** // * Removes a drop target from the given control. // * // * @param control // * @param target // */ // public static void removeDragTarget(Control control, // IDragOverListener target) { // if (control == null) { // defaultTargets.remove(target); // } else { // List targetList = getTargetList(control); // if (targetList != null) { // targetList.remove(target); // if (targetList.isEmpty()) { // control.setData(DROP_TARGET_ID, null); // } // } // } // } /** * Shorthand method. Returns the bounding rectangle for the given control, in * display coordinates. Note that all 'Shell' controls are expected to be 'top level' * so DO NOT do the origin offset for them. * * @param draggedItem * @param boundsControl * @return */ public static Rectangle getDisplayBounds(Control boundsControl) { Control parent = boundsControl.getParent(); if (parent == null || boundsControl instanceof Shell) { return boundsControl.getBounds(); } return Geometry.toDisplay(parent, boundsControl.getBounds()); } // RAP [rh] DnD not implemented // public static boolean performDrag(final Object draggedItem, // Rectangle sourceBounds, Point initialLocation, boolean allowSnapping) { // // IDropTarget target = dragToTarget(draggedItem, sourceBounds, // initialLocation, allowSnapping); // // if (target == null) { // return false; // } // // target.drop(); // // // If the target can handle a 'finished' notification then send one // if (target!= null && target instanceof IDropTarget2) { // ((IDropTarget2)target).dragFinished(true); // } // // return true; // } // RAP [rh] DnD not implemented // /** // * Drags the given item to the given location (in display coordinates). This // * method is intended for use by test suites. // * // * @param draggedItem object being dragged // * @param finalLocation location being dragged to // * @return true iff the drop was accepted // */ // public static boolean dragTo(Display display, Object draggedItem, // Point finalLocation, Rectangle dragRectangle) { // Control currentControl = SwtUtil.findControl(display, finalLocation); // // IDropTarget target = getDropTarget(currentControl, draggedItem, // finalLocation, dragRectangle); // // if (target == null) { // return false; // } // // target.drop(); // // return true; // } // RAP [rh] DnD not implemented // /** // * Forces all drags to end at the given position (display coordinates). Intended // * for use by test suites. If this method is called, then all subsequent calls // * to performDrag will terminate immediately and behave as though the object were // * dragged to the given location. Calling this method with null cancels this // * behavior and causes performDrag to behave normally. // * // * @param forcedLocation location where objects will be dropped (or null to // * cause drag/drop to behave normally). // */ // public static void forceDropLocation(TestDropLocation forcedLocation) { // forcedDropTarget = forcedLocation; // } // RAP [rh] DnD not implemented // /** // * Drags the given item, given an initial bounding rectangle in display coordinates. // * Due to a quirk in the Tracker class, changing the tracking rectangle when using the // * keyboard will also cause the mouse cursor to move. Since "snapping" causes the tracking // * rectangle to change based on the position of the mouse cursor, it is impossible to do // * drag-and-drop with the keyboard when snapping is enabled. // * // * @param draggedItem object being dragged // * @param sourceBounds initial bounding rectangle for the dragged item // * @param initialLocation initial position of the mouse cursor // * @param allowSnapping true iff the rectangle should snap to the drop location. This must // * be false if the user might be doing drag-and-drop using the keyboard. // * // * @return // */ // static IDropTarget dragToTarget(final Object draggedItem, // final Rectangle sourceBounds, final Point initialLocation, // final boolean allowSnapping) { // final Display display = Display.getCurrent(); // // // Testing...immediately 'drop' onto the test target // if (forcedDropTarget != null) { // Point location = forcedDropTarget.getLocation(); // // Control currentControl = SwtUtil.findControl(forcedDropTarget.getShells(), location); // return getDropTarget(currentControl, draggedItem, location, // sourceBounds); // } // // // Create a tracker. This is just an XOR rect on the screen. // // As it moves we notify the drag listeners. // final Tracker tracker = new Tracker(display, SWT.NULL); // tracker.setStippled(true); // // tracker.addListener(SWT.Move, new Listener() { // public void handleEvent(final Event event) { // display.syncExec(new Runnable() { // public void run() { // // Get the curslor location as a point // Point location = new Point(event.x, event.y); // // // Select a drop target; use the global one by default // IDropTarget target = null; // // Control targetControl = display.getCursorControl(); // // // Get the drop target for this location // target = getDropTarget(targetControl, // draggedItem, location, // tracker.getRectangles()[0]); // // // Set up the tracker feedback based on the target // Rectangle snapTarget = null; // if (target != null) { // snapTarget = target.getSnapRectangle(); // // tracker.setCursor(target.getCursor()); // } else { // tracker.setCursor(DragCursors // .getCursor(DragCursors.INVALID)); // } // // // If snapping then reset the tracker's rectangle based on the current drop target // if (allowSnapping) { // if (snapTarget == null) { // snapTarget = new Rectangle(sourceBounds.x // + location.x - initialLocation.x, // sourceBounds.y + location.y // - initialLocation.y, // sourceBounds.width, sourceBounds.height); // } // // // Try to prevent flicker: don't change the rectangles if they're already in // // the right location // Rectangle[] currentRectangles = tracker.getRectangles(); // // if (!(currentRectangles.length == 1 && currentRectangles[0] // .equals(snapTarget))) { // tracker.setRectangles(new Rectangle[] { snapTarget }); // } // } // } // }); // } // }); // // // Setup...when the drag starts we might already be over a valid target, check this... // // If there is a 'global' target then skip the check // IDropTarget target = null; // Control startControl = display.getCursorControl(); // // if (startControl != null && allowSnapping) { // target = getDropTarget(startControl, // draggedItem, initialLocation, // sourceBounds); // } // // // Set up an initial tracker rectangle // Rectangle startRect = sourceBounds; // if (target != null) { // Rectangle rect = target.getSnapRectangle(); // // if (rect != null) { // startRect = rect; // } // // tracker.setCursor(target.getCursor()); // } // // if (startRect != null) { // tracker.setRectangles(new Rectangle[] { Geometry.copy(startRect)}); // } // // // Tracking Loop...tracking is preformed on the 'SWT.Move' listener registered // // against the tracker. // // // HACK: // // Some control needs to capture the mouse during the drag or other // // controls will interfere with the cursor // Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); // if (shell != null) { // shell.setCapture(true); // } // // // Run tracker until mouse up occurs or escape key pressed. // boolean trackingOk = tracker.open(); // // // HACK: // // Release the mouse now // if (shell != null) { // shell.setCapture(false); // } // // // Done tracking... // // // Get the current drop target // IDropTarget dropTarget = null; // Point finalLocation = display.getCursorLocation(); // Control targetControl = display.getCursorControl(); // dropTarget = getDropTarget(targetControl, draggedItem, // finalLocation, tracker.getRectangles()[0]); // // // Cleanup... // tracker.dispose(); // // // if we're going to perform a 'drop' then delay the issuing of the 'finished' // // callback until after it's done... // if (trackingOk) { // return dropTarget; // } // else if (dropTarget!= null && dropTarget instanceof IDropTarget2) { // // If the target can handle a 'finished' notification then send one // ((IDropTarget2)dropTarget).dragFinished(false); // } // // return null; // } // RAP [rh] DnD not implemented // /** // * Given a list of IDragOverListeners and a description of what is being dragged, it returns // * a IDropTarget for the current drop. // * // * @param toSearch // * @param mostSpecificControl // * @param draggedObject // * @param position // * @param dragRectangle // * @return // */ // private static IDropTarget getDropTarget(List toSearch, // Control mostSpecificControl, Object draggedObject, Point position, // Rectangle dragRectangle) { // if (toSearch == null) { // return null; // } // // Iterator iter = toSearch.iterator(); // while (iter.hasNext()) { // IDragOverListener next = (IDragOverListener) iter.next(); // // IDropTarget dropTarget = next.drag(mostSpecificControl, // draggedObject, position, dragRectangle); // // if (dropTarget != null) { // return dropTarget; // } // } // // return null; // } // RAP [rh] DnD not implemented // /** // * Returns the drag target for the given control or null if none. // * // * @param toSearch // * @param e // * @return // */ // public static IDropTarget getDropTarget(Control toSearch, // Object draggedObject, Point position, Rectangle dragRectangle) { // // Search for a listener by walking the control's parent hierarchy // for (Control current = toSearch; current != null; current = current // .getParent()) { // IDropTarget dropTarget = getDropTarget(getTargetList(current), // toSearch, draggedObject, position, dragRectangle); // // if (dropTarget != null) { // return dropTarget; // } // // // Don't look to parent shells for drop targets // if (current instanceof Shell) { // break; // } // } // // // No controls could handle this event -- check for default targets // return getDropTarget(defaultTargets, toSearch, draggedObject, position, // dragRectangle); // } /** * Returns the location of the given event, in display coordinates * @return */ public static Point getEventLoc(Event event) { Control ctrl = (Control) event.widget; return ctrl.toDisplay(new Point(event.x, event.y)); } }